Skip to content

fix(android): Defer frame metrics reflection during init - #5886

Merged
0xadam-brown merged 3 commits into
mainfrom
fix/no-reflection-on-main-thread
Aug 5, 2026
Merged

fix(android): Defer frame metrics reflection during init#5886
0xadam-brown merged 3 commits into
mainfrom
fix/no-reflection-on-main-thread

Conversation

@0xadam-brown

@0xadam-brown 0xadam-brown commented Aug 4, 2026

Copy link
Copy Markdown
Member

📜 Description

Moves Choreographer private field lookup out of the frame metrics collector constructor so that Sentry.init() doesn't synchronously perform framework reflection. Helps us reduce the likelihood of another common class of init ANRs (see here).

💡 Motivation and Context

We've seen 583k ANR events involving the SentryFrameMetricsCollector across 257 affected users since November 2024 (link), making it the highest-volume SDK-caused ANR we track.

Those numbers got lots better thanks to @runningcode's fix in #5641: events peaked at ~12k per 3-day window in June 2026, then dropped sharply to (a fairly consistent) ~4k/3d. But the reflection this PR addresses continues to contribute to those remaining ANRs across all SDK versions, including the newest ones.

Any behavior changes?

Behavior change from the user's perspective should be nonexistant in most cases, and minor in the worst case.

The choreographer and choreographerLastFrameTimeField properties are still initialized by a main-thread Handler post made during collector construction, before later startCollection() calls post frame-listener registration work to the same main looper. Since those main looper tasks run in order, the Choreographer fallback should be populated before any collected frame or pending-frame interpolation normally needs it. If it's not ready yet, the failure mode is a missed/less precise first pending-frame calculation rather than a crash.

💚 How did you test it?

Unit tests + manual smoke tests on Android sample app.

📝 Checklist

  • I added GH Issue ID & Linear ID
  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog.
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.
  • Public API changes reviewed by another Mobile SDK team member or implemented according to the develop docs spec.

🔮 Next steps

@0xadam-brown
0xadam-brown force-pushed the fix/no-reflection-on-main-thread branch from e23fd78 to 1420ac9 Compare August 4, 2026 11:48
@sentry

sentry Bot commented Aug 4, 2026

Copy link
Copy Markdown

📲 Install Builds

Android

🔗 App Name App ID Version Configuration
SDK Size io.sentry.tests.size 8.51.0 (1) release

⚙️ sentry-android Build Distribution Settings

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 339.51 ms 435.98 ms 96.47 ms
Size 0 B 0 B 0 B

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
455eb6e 341.51 ms 428.96 ms 87.45 ms
d15471f 343.13 ms 361.47 ms 18.34 ms
b193867 331.08 ms 397.06 ms 65.98 ms
5b1a06b 315.40 ms 353.33 ms 37.94 ms
62b579c 312.88 ms 361.57 ms 48.70 ms
85d7417 347.21 ms 394.35 ms 47.15 ms
6dff1c9 298.04 ms 327.43 ms 29.39 ms
5b1a06b 310.56 ms 362.79 ms 52.22 ms
ee747ae 386.94 ms 431.43 ms 44.49 ms
462dea2 322.40 ms 370.06 ms 47.66 ms

App size

Revision Plain With Sentry Diff
455eb6e 0 B 0 B 0 B
d15471f 1.58 MiB 2.13 MiB 559.54 KiB
b193867 1.58 MiB 2.19 MiB 620.00 KiB
5b1a06b 0 B 0 B 0 B
62b579c 0 B 0 B 0 B
85d7417 1.58 MiB 2.10 MiB 533.44 KiB
6dff1c9 0 B 0 B 0 B
5b1a06b 0 B 0 B 0 B
ee747ae 1.58 MiB 2.10 MiB 530.95 KiB
462dea2 0 B 0 B 0 B

Previous results on branch: fix/no-reflection-on-main-thread

Startup times

Revision Plain With Sentry Diff
75ec6d9 324.23 ms 374.78 ms 50.55 ms
562fe79 315.31 ms 356.63 ms 41.32 ms

App size

Revision Plain With Sentry Diff
75ec6d9 0 B 0 B 0 B
562fe79 0 B 0 B 0 B

Moves Choreographer private field lookup out of the frame metrics collector constructor so SDK init does not synchronously perform framework reflection on the calling thread. Helps us reduce the likelihood of another common class of Sentry.init() ANRs (see [here](https://sentry.sentry.io/issues/6138715212/?project=4506812075540480&referrer=seer.agent.in-chat-link)).

Behavior change from the user's perspective should usually be non-existant, and minor in the worst case. The choreographer and choreographerLastFrameTimeField properties are still initialized by a main-thread Handler post made during collector construction, before later startCollection() calls post frame-listener registration work to the same main looper. Since those main-looper tasks run in order, the Choreographer fallback should be populated before any collected frame or pending-frame interpolation normally needs it. If it's not ready yet, the failure mode is a missed/less precise first pending-frame calculation rather than a crash.

Co-Authored-By: OpenCode <noreply@opencode.ai>
@0xadam-brown
0xadam-brown force-pushed the fix/no-reflection-on-main-thread branch from 1420ac9 to ec477f3 Compare August 4, 2026 12:02
@0xadam-brown
0xadam-brown marked this pull request as ready for review August 4, 2026 12:06
@0xadam-brown 0xadam-brown added the sanity-check PR needs a lightweight review for obvious issues label Aug 4, 2026

@runningcode runningcode left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good with one nit! Thanks for taking this further!

@0xadam-brown
0xadam-brown merged commit 52bd5a7 into main Aug 5, 2026
71 of 72 checks passed
@0xadam-brown
0xadam-brown deleted the fix/no-reflection-on-main-thread branch August 5, 2026 09:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

sanity-check PR needs a lightweight review for obvious issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants